import java.util.Vector;


public class Actions
{
	
	public static class Coordinate {
		public double x;
		public double y;
		
		public Coordinate() {
			x = 0;
			y = 0;
		}
		
		public Coordinate(double x, double y) {
			this.x = x;
			this.y = y;
		}
	}
	
	private static double SQR(double a)
	{
		return a*a;		
	}
	
	//Test dribble ball
	public static void DribbleBallToRightSide(Player p)
	{
		int kickAngle = (int) p.getAngle() * -1;
		tryDribbleBall(p, 50, 10, kickAngle);
	}
	
	public static boolean tryDribbleBall(Player p, int runPower, int kickPower, int direction)
	{
		if( p.isBallWithinKickingDistance() )
		{
			double kickEffectivePower = kickEffective(p, kickPower, direction);
			System.out.println("Kicking Dir: " + direction + ", Pow: " + kickPower + ", myAng: " + p.getAngle());
			//System.out.println("Kicking Power: " + kickEffectivePower);
			kickThenDelay(p, kickPower, direction);
			return true;
		}
		else
		{
			findBallAndGotoBall(p, runPower);
			return false;
		}
	}
	
	private static void kickThenDelay(Player p, int power, int direction)
	{
		p.kick(power, direction);				
		try { 
			Thread.sleep(150); // El thread se duerme.
		} catch (InterruptedException ex) {
			System.out.println("Error en " + ex.toString());
		}
			
	}
	
	public static void scoreGoal(Player p){
		double distanceToGoal =p.getWorldModel().getWorld()[1][11].distance;
		double directionToGoal = p.getWorldModel().getWorld()[1][11].direction;
		double newDirectionToGoal = p.getWorldModel().getOpponentAngle(12);
		ShootingMetaData trajectories=new ShootingMetaData();
		int playerSpeed = 80;
		
		if (distanceToGoal<15) 
		{
			Metaheuristic.InitShootingAnglesAndTrajectories(p, trajectories); //en esta funcion se define la trayectoria que seguira la bola.
			if(p.isBallWithinKickingDistance())
			{
				System.out.println("Goal kick Angle: "+ newDirectionToGoal + ", myAng: " + p.getAngle());
				kickThenDelay(p, 100, (int)newDirectionToGoal);
			} 
			else
			{
				findBallAndGotoBall(p, playerSpeed);
			}
			
		} 
		else 
		{
			tryDribbleBall(p, playerSpeed, 20, (int)newDirectionToGoal);
		}
	}
	
	
	public static void findBallAndGotoBall(Player p, int power)
	{
		if(p.isBallVisible())
			Actions.goTowardsBall( p, power );
		else
			Actions.searchForBall( p );
	}
	
	public static void searchForBall(Player p)
	{
		Vector<Double> ballInfo = p.getBall();
		int size = ballInfo.size();
		if(size == 0)
		{
			p.turn(45, true);			
		}
		else if(size == 1)
		{
			double ballDirection = ballInfo.elementAt(0);
			if( Auxiliar.isBetween(15, -15, ballDirection  ) )
			{
				p.dash(70, true);
			}
			else 
			{
				p.turn( (int) ballDirection , true);
			}
		}
		else 
		{
			//Congrats! You have found the ball!
			System.out.println("You have found the ball!");
		}
		
	}
	
	public static void goTowardsBall( Player p, int power) //assumes close proximity to ball
	{
		Vector<Double> ballInfo = p.getBall();
		if(ballInfo.size() >= 2) {
			double direction = ballInfo.elementAt(1);
			if( Auxiliar.isBetween(15, -15, direction) )
			{
				
				if(ballInfo.elementAt(0) <= .6)
				{
					//do nothing because you passed the ball
				}
				else
				{
					p.dash(power, true);
				}
			}
			else
			{
				p.turn( (int) direction, true );
			}
		}
		else
		{
			//p.turn( Auxiliar.getMaxModOfNumber( (int) direction, 30)  );
			p.turn( 45, true);
		}
	}
	
	public static double kickEffective(Player p, int power, int angle){
		//Check that the power is in the limits
	
		int minpower = Integer.parseInt( p.getServerParam("minpower") );
		int maxpower = Integer.parseInt( p.getServerParam("maxpower") );
		int minmoment = Integer.parseInt( p.getServerParam("minmoment") );
		int maxmoment = Integer.parseInt( p.getServerParam("maxmoment") );
		
		
		if(power <  minpower)
			power = minpower;
		else if(power > maxpower)
			power = maxpower;
		if(angle < minmoment)
			angle = minmoment;
		else if(angle > maxmoment)
			angle = maxmoment;
			
		//Calculate de power needed for a the desired effective power
		World worldModel = p.getWorldModel();
		String kickPowerRateString =  p.getServerParam("kick_power_rate");
		double kickPowerRate = Double.parseDouble(kickPowerRateString);
		double kickableMargin = Double.parseDouble( p.getServerParam("kickable_margin"));
		double dir_diff = worldModel.getWorld()[1][12].getDirection();
		double dist_ball = worldModel.getBallDistance();
		double ep = power/kickPowerRate*(1-0.25*(dir_diff/180)-0.25*(dist_ball/kickableMargin));
		
		//Check that the power caluclated is in the limits
		if(ep < minpower)
			ep = minpower;
		else if(ep > maxpower)
			ep = maxpower;
		return ep;
		//p.kick( (int) ep ,angle);
	}

		//No cuenta con que va estar moviendose y girando al mismo tiempo
		//Supone que solo van a llegar valores positivos para power
		//y en caso de que a la posicion que se desea llegar esta atras y
		//esta en un cierto limite de distancia y angulo se mueve hacia atras
		public static void goToPos(Player p, int x, int y, int power)
		{

			int maxpower = Integer.parseInt( p.getServerParam("maxpower") );
			
			if(power < 0)
				power = 0;
			else if(power > maxpower)
				power = maxpower;
				
			int turnAngle = (int) Math.atan2( (double) y - p.getY(), (double) x - p.getX() );
				
			//Check the distance to travel		
			double maxDistBackwards = Double.parseDouble( p.getServerParam("maxDistBackwards") );
			double maxAngleBackwards = Double.parseDouble( p.getServerParam("maxAngleBackwards") );
			if( Math.sqrt( SQR( y-p.getY() ) + SQR( x-p.getX() ) ) < maxDistBackwards){
				if(turnAngle<(maxAngleBackwards-180)){
					turnAngle += 180;
					p.turn(turnAngle, true);
					p.dash((-1)*power, true);
				}
				else if(turnAngle<(180-maxAngleBackwards)) {
					turnAngle -= 180;
					p.turn(turnAngle, true);
					p.dash((-1)*power, true);
				}
			}
			else{
				p.turn(turnAngle, true);
				p.dash(power, true);}
		}
	
		
		public static void goToHomePosition(Player player) {
			
			int angleToTurn = player.recordAngle;
			int dashToMove = player.recordDash;
			
			angleToTurn = -angleToTurn;
			
			if(angleToTurn < 5 && angleToTurn > -5) {
					if(dashToMove < 100) {
						System.out.println("Dash:" + dashToMove);
						player.dash(dashToMove);
						player.recordDash = 0;
						player.kickedBall = false;
					} else {
						System.out.println("Dash: 100");
						player.dash(100);
						player.recordDash -= 100;
					}
			}
			else {
				System.out.println("Turn: " + angleToTurn);
				player.turn(angleToTurn);
				player.recordAngle = 0;
			}
			
		}
	
		/*
		public static void goalieCatchBall(Player player) {
			double xLeftP = -52.5;
			double yLeftP = -7;
			double xRightP = -52.5;
			double yRightP = 7;
			
			Coordinate playerPos = new Coordinate(); 
			boolean gotPosition = player.getXYGoalie(playerPos);
			double xP = playerPos.x;
			double yP = playerPos.y;
			
			if(gotPosition) {
				System.out.print("X: " + xP + " Y: " + yP + " - ");
				
				World world = player.getWorldModel();
				double xLeft = Math.sqrt( Math.pow(xLeftP - xP, 2) + Math.pow(yLeftP - yP, 2));		//x1
				double xRight = Math.sqrt( Math.pow(xRightP - xP, 2) + Math.pow(yRightP - yP, 2));	//x2
				
				//System.out.print("xLeft Dist: " + xLeft + "  xRight Dist:" + xRight + " ");
				double ballDistance = world.getBallDistance();		//r
				double verticalAngle = player.getAngle();			//o
				double a = Math.sqrt(
								Math.pow(ballDistance, 2) 
								+ Math.pow(xRight, 2)
								- ballDistance * xRight * Math.cos(90 - verticalAngle)
							);
				
				double b = Math.sqrt(
								Math.pow(ballDistance, 2)
								+ Math.pow(xLeft, 2)
								- ballDistance * xLeft * Math.cos(90 + verticalAngle)
							);
				
				double alpha = Math.acos(
									(
										Math.pow(a, 2)
										+ Math.pow(b, 2)
										- Math.pow((xLeft + xRight), 2)
									)
									/ (a * b)
								);
				
				//	 r'=a*sin(alpha/2)/sin(90+o-alpha/2)-x2
				double rPrime = a * Math.sin(alpha / 2)
								/ Math.sin(90 + verticalAngle - alpha / 2)
								- xRight;
				
				System.out.println("angle: " + verticalAngle + " a: " + a + " b: " + b + " alpha: " + alpha + " rPrime: " + rPrime);
				
				
			} else {
				System.out.println("NOT PRIME");
			}
		}
		*/
		
		public static void goalieCatchBall(Player player) {
			World world = player.getWorldModel();
			double ballDistance = world.getBallDistance();
			double ballDirection = world.getBallDirection();
			
			double catchable_area_l = Double.parseDouble(player.getServerParam("catchable_area_l"));
			double catchable_area_w = Double.parseDouble(player.getServerParam("catchable_area_w"));
			
			if(ballDistance > 8 && ballDirection > 10 && ballDirection < -10 ) {
				player.turn((int)ballDirection, true);
			} else if(ballDistance > 5 && ballDirection < 10 && ballDirection > -10) {
				player.catchBall((int)ballDirection);
			}
			
			
		}
		
		public void doPass(Player p,World w){ //Metodo para hacer un pase directo
    		int i = 0;
    		double allyDist[]=new double[10];
    		double oppDist []=new double[11];
    		double allyAngl []=new double[10];
    		double oppAngl []=new double[11];
    		//int t = p.getTime();
    		//double tdiff;
    		int indexAl = 0,indexOp = 0;
    		
    		//TODO:Agregar la parte de la probabilidad (timestamp) para determinar si sigue ahi el oponente o aliado
    		for (i = 0; i < 10; i++){
    			allyDist[i]=w.getAllyDistance(i);
        		allyAngl[i]=w.getAllyAngle(i);
        		oppDist[i]=w.getOpponentDistance(i);
            }
    		
            double near= Auxiliar.getMinValue(allyDist); //TODO:Establecer un valor medio de distancia para el pase
            double nearOp= Auxiliar.getMinValue(oppDist);
                       
            for (i = 0; i < allyDist.length; i++) {
                if(Double.toString(near).equals(Double.toString(allyDist[i])) &&  i != p.getNumber()) {
                    indexAl=i;
                }
            }
            for (i = 0; i < oppDist.length; i++) {
                if(Double.toString(nearOp).equals(Double.toString(oppDist[i]))) {
                    indexOp=i;
                }
            }
            
    		if (!Auxiliar.isBetween(allyAngl[indexAl]+10, allyAngl[indexAl]-10, oppAngl[indexOp])){
    			p.kick((int)near,(int)allyAngl[indexAl]); 
    		}else {
    			p.turn(45, true);
    			doPass(p,w); // en caso de no poder realizar un pase, gira 45 grados y realiza el mismo procedimiento ya que es necesario que haga un pase
    		}
    	}
		
		public static void takeCareOfArea(Player player) {
			int playerNum = player.getNumber();
			
			switch(playerNum) {
				case 1:
					//Goalie
					break;
				case 10:
				case 11:
					//Atack
					break;
				default:
					//CareArea
					World world = player.getWorldModel();
					double ballDistance = world.getBallDistance();
					double ballDirection = world.getBallDirection();
					double widthArea = 26.25;
					double heightArea = 17;
					double r = heightArea;
					int opponentGoalDirection = (int)world.getOpponentAngle(11);
					
					if(ballDistance < heightArea && !player.kickedBall) {
						//(Player p, int runPower, int kickPower, int direction)
						//System.out.println("Kick IT!");
						player.kickedBall = tryDribbleBall(player, 80, 100, opponentGoalDirection);
					}
					if(player.kickedBall) {
						System.out.println("Go Home!");
						goToHomePosition(player);
					} else {
						player.turn(20);
					}
					break;
			}
		}
}
